//@ts-nocheck
import { useContext, useEffect, useRef, useState } from 'react';
import { Context } from './provider';

const isEqual = Object.is;

export const useModel = (namespace: string, selector?: (value: any) => any) => {
  const { dispatcher } = useContext(Context);
  const selectorRef = useRef(selector);
  selectorRef.current = selector;
  const [state, setState] = useState(() =>
    selectorRef.current
      ? selectorRef.current(dispatcher.data[namespace])
      : dispatcher.data[namespace],
  );
  const stateRef = useRef<any>(state);
  stateRef.current = state;

  const isMount = useRef(false);
  useEffect(() => {
    isMount.current = true;
    return () => {
      isMount.current = false;
    };
  }, []);

  useEffect(() => {
    const handler = (data: any) => {
      if (!isMount.current) {
        // 如果 handler 执行过程中，组件被卸载了，则强制更新全局 data
        // TODO: 需要加个 example 测试
        setTimeout(() => {
          dispatcher.data[namespace] = data;
          dispatcher.update(namespace);
        });
      } else {
        const currentState = selectorRef.current
          ? selectorRef.current(data)
          : data;
        const previousState = stateRef.current;
        if (!isEqual(currentState, previousState)) {
          // 避免 currentState 拿到的数据是老的，从而导致 isEqual 比对逻辑有问题
          stateRef.current = currentState;
          setState(currentState);
        }
      }
    };
    dispatcher.callbacks[namespace] ||= new Set() as any; // rawModels 是 umi 动态生成的文件，导致前面 callback[namespace] 的类型无法推导出来，所以用 as any 来忽略掉
    dispatcher.callbacks[namespace].add(handler);
    dispatcher.update(namespace);

    return () => {
      dispatcher.callbacks[namespace]?.delete(handler);
    };
  }, [namespace]);

  return state;
};
